﻿using UnityEngine;
using System.Collections;

public class GameObjectPool
{
    //private static GameObjectPool self;

    private GameObject prefab;

    private Stack available;
    
    private ArrayList all;

    public delegate void InitializationFunction(GameObject obj);
    public InitializationFunction initializationFunction;

    private bool setActiveRecursively;

    public GameObjectPool() { }

    //public static GameObjectPool getInstance()
    //{
    //    if (self == null)
    //    {
    //        self = new GameObjectPool();
    //    }
    //    return self;
    //}

    public void InitGameObjectPool(GameObject prefab, int initialCapacity, InitializationFunction initializationFunction, bool setActiveRecursively)
    {
        this.prefab = prefab;
        if (initialCapacity > 0)
        {
            this.available = new Stack(initialCapacity);
            this.all = new ArrayList(initialCapacity);
        }
        else
        {
            this.available = new Stack();
            this.all = new ArrayList();
        }
        this.initializationFunction = initializationFunction;
        this.setActiveRecursively = setActiveRecursively;
    }

    public GameObject Spawn(Vector3 position)
    {
        GameObject result;

        if (available.Count == 0)
        {
            //result = GameObject.Instantiate(prefab, position, rotation) as GameObject;
            result = GameObject.Instantiate(prefab) as GameObject;
            result.transform.position = position;
            if (initializationFunction != null)
            {
                initializationFunction(result);
            }
            // Keep track of it.
            all.Add(result);
        }
        else
        {
            result = available.Pop() as GameObject;

            Transform resultTrans = result.transform;
            resultTrans.position = position;
            //resultTrans.rotation = rotation;

            this.SetActive(result, true);
        }
        return result;
    }


    public bool Unspawn(GameObject obj)
    {
        if (!available.Contains(obj))
        { 
            available.Push(obj);
            this.SetActive(obj, false);
            return true;
        }
        return false;
    }


    public void PrePopulate(int count)
    {
        GameObject[] array = new GameObject[count];
        for (int i = 0; i < count; i++)
        {
            array[i] = Spawn(Vector3.zero);
            this.SetActive(array[i], false);
        }
        for (int j = 0; j < count; j++)
        {
            Unspawn(array[j]);
        }
    }

    public void UnspawnAll()
    {
        for (int i = 0; i < all.Count; i++)
        {
            GameObject obj = all[i] as GameObject;
            if (obj.activeSelf)
                Unspawn(obj);
        }
    }

    public void Clear()
    {
        UnspawnAll();
        available.Clear();
        all.Clear();
    }

    public int GetActiveCount()
    {
        return all.Count - available.Count;
    }

    public int GetAvailableCount()
    {
        return available.Count;
    }

    GameObject GetPrefab()
    {
        return prefab;
    }

    public void ForEach(InitializationFunction func, bool activeOnly)
    {
        for (int i = 0; i < all.Count; i++)
        {
            GameObject obj = all[i] as GameObject;
            if (!activeOnly || obj.activeSelf)
            {
                func(obj);
            }
        }
    }

    private void SetActive(GameObject obj, bool val)
    {
        obj.SetActive(val);
    }
}